package Controller;

import java.util.HashMap;
import java.util.List;
import java.util.SortedSet;
import java.util.TreeSet;

import model.MovieEvent;
import model.Result;
import model.EventProperties.MotionEventProperties;
import model.EventProperties.PushMsgEventProperties;
import model.EventProperties.ReadFladEventProperties;
import Enums.EventType;
import Mqtt.MyMqqtClient;
import android.app.PendingIntent;
import android.app.PendingIntent.OnFinished;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.view.GestureDetector.OnDoubleTapListener;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;

public class EventManager implements  OnClickListener,OnTouchListener,OnFinished,
	OnDoubleTapListener, SensorEventListener, OnCompletionListener{
	SortedSet<Integer> listedEvents ;
	int i;
	public GameController controller;
	SensorManager sManager;
	int numOfSensorListiners;
	HashMap<Integer, MyMqqtClient> eventIdToMqqtClient;
	
	public EventManager(GameController controller, SensorManager sm) {
		listedEvents = new TreeSet<Integer>();
		this.controller = controller;
		sManager = sm;
		initSensors();
		eventIdToMqqtClient = new HashMap<Integer, MyMqqtClient>();
	}
	
	private void initSensors()
	{
		if (sManager != null)
		{
			List<Sensor> liste = sManager.getSensorList(Sensor.TYPE_ORIENTATION);
			sManager.registerListener(this, liste.get(0), SensorManager.SENSOR_DELAY_UI);
		}
	}
	
	@Override
	public void onAccuracyChanged(Sensor sensor, int accuracy) {
	}

	@Override
	public synchronized void onSensorChanged(SensorEvent e) {
		try {
			if (numOfSensorListiners == 0 || sManager == null)
				return;
			for (int eventIndex : listedEvents) {
				MovieEvent event = controller.getCurrentMovieEvent(eventIndex);
				if (event.getType() == EventType.motion) {
					boolean wasDetected = ((MotionEventProperties) event
							.getProperties()).detectMotion(e);
					if (wasDetected) {
						try {
							controller.eventOccurred(event.getId());
						} catch (Exception e1) {
							controller.raiseErrorMessage(e1.getMessage());
						}
						return;
					}
				}
			}
		} catch (Exception e2) {
			String msg = e2.getMessage();
			Log.d("bug", msg);
		}
	}

	public void removeListedEvent(MovieEvent event)
	{
		int eventId =  event.getId();
		if (listedEvents.contains(eventId))
		{
			switch (event.getType()) {
			case motion:
				this.unregisterMotionEvent(event);
				break;
			case pushMsg:
				eventIdToMqqtClient.get(eventId).quit();
				eventIdToMqqtClient.remove(eventId);
				break;
			default:
				break;
			}

			listedEvents.remove(event.getId());
		}
	}
	
	public void removeListedEvent(int eventId)
	{
		listedEvents.remove(eventId);
	}

	public void addListedEvent(MovieEvent event) {
		boolean isImmediateEvent  = false;
		switch (event.getType()) {
		case motion:
			this.registerMotionEvent(event);
			break;
		case pushMsg:
		{
			PushMsgEventProperties pushProp = (PushMsgEventProperties) event.getProperties();
			MyMqqtClient client = new MyMqqtClient("yuval", controller, event, pushProp.getMsgName());
			eventIdToMqqtClient.put(event.getId(), client);
			break;
		}
		case readFlag:
		{
			isImmediateEvent = true;
			try {
				//get the flag name from the event
				String flagName = ((ReadFladEventProperties)event.getProperties()).getFlagName();
				
				//if such event exist
				if(controller.getFlags().get(flagName) != null)
				{
					//if the flag value is true
					if(controller.getFlags().get(flagName))
					{
						//activate the yes Results
						controller.eventOccurred(event.getId());
					}
					else //if the flag value is false then activate the NoResult
					{
						for (Result result : event.getResultNo()) {
							try {
								controller.performResult(event.getId(),result);
							} catch (Exception e) {
								controller.raiseErrorMessage(e.getMessage());
							}
						}
					}
				}
			} catch (Exception e) {
				controller.raiseErrorMessage(e.getMessage());
			}
			break;
		}
		default:
			break;
		}
		
		if (!isImmediateEvent)
		{
			listedEvents.add(event.getId());
		}
	}


	@Override
	public void onClick(View v) {
		if (listedEvents.contains(v.getId()))
		{
			try {
				controller.eventOccurred(v.getId());
			} catch (Exception e) {
				controller.raiseErrorMessage(e.getMessage());
			}
		}
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		return false;
	}

	@Override
	public void onSendFinished(PendingIntent pendingIntent, Intent intent,
			int resultCode, String resultData, Bundle resultExtras) {
	}

	@Override
	public boolean onDoubleTap(MotionEvent e) {
		return false;
	}

	@Override
	public boolean onDoubleTapEvent(MotionEvent e) {
		return false;
	}

	@Override
	public boolean onSingleTapConfirmed(MotionEvent e) {
		return false;
	}

	@Override
	public void onCompletion(MediaPlayer mp) {
			try {
				controller.movieEnded();
			} catch (Exception e) {
				System.out.print(e.getMessage());
			
				controller.raiseErrorMessage(e.getMessage());
			}
	}

	private void registerMotionEvent(MovieEvent event) {
		if (numOfSensorListiners == 0 && sManager != null)
		{
			SensorManager sManager = (SensorManager)controller.getView().getSystemService( Context.SENSOR_SERVICE ); 
	        
	        List<Sensor> liste = sManager.getSensorList(Sensor.TYPE_ACCELEROMETER | Sensor.TYPE_ORIENTATION | Sensor.TYPE_GYROSCOPE); 

	        for(int a=0;a<liste.size();a++) { 
		        sManager.registerListener(this, liste.get(a), SensorManager.SENSOR_DELAY_NORMAL); 
	        } 
		}
		
		listedEvents.add(event.getId());
		numOfSensorListiners++;
	}
	
	private void unregisterMotionEvent(MovieEvent event) {
		numOfSensorListiners--;
		if (numOfSensorListiners == 0)
		{
			//unregisterAllMotionEvents();
		}
	}
	
	public void unregisterAllMotionEvents()
	{
		if (controller.EMULATOR_MODE)
			return;
		try
		{
			SensorManager sManager = (SensorManager)controller.getView().getSystemService( Context.SENSOR_SERVICE ); 
	        
	        List<Sensor> liste = sManager.getSensorList(Sensor.TYPE_ORIENTATION); 

	        for(int a=0;a<liste.size();a++) { 
		        sManager.unregisterListener(this, liste.get(a)); 
	        }
		}
		catch(Exception e)//It's ok... 
		{
			Log.d("DEBUG", e.getMessage());
		}
	}


}
